package com.loeng.framework.common.util.collection;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static java.util.Arrays.asList;

/**
 * Collection 工具类
 * @author loeng zhuo
 */
public class CollectionUtils {

    /**
     * 将 source 转换为 List<T>
     * @param source 源数据
     * @param func 转换函数
     * @param <T> 转换后的类型
     * @return 转换后的 List
     */
    public static <S, T> List<T> convertList(Collection<S> source, Function<S, T> func) {
        if (CollUtil.isEmpty(source)) {
            return new ArrayList<>();
        }
        return source.stream().map(func).filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 将 source 转换为 Set<T>
     * @param from 源数据
     * @param <T> 转换后的类型
     * @return 转换后的 Set
     */
    public static <T> Set<T> convertSet(Collection<T> from) {
        return convertSet(from, v -> v);
    }

    /**
     * 将 source 转换为 Set<T>
     * @param from 源数据
     * @param func 转换函数
     * @param <T> 转换前的类型
     * @param <U> 转换后的类型
     * @return 转换后的 Set
     */
    public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
        if (CollUtil.isEmpty(from)) {
            return new HashSet<>();
        }
        return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    /**
     * 将 source 转换为 Set<T>
     * @param from 源数据
     * @param func 转换函数
     * @param filter 过滤函数
     * @param <T> 转换前的类型
     * @param <U> 转换后的类型
     * @return 转换后的 Set
     */
    public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
        if (CollUtil.isEmpty(from)) {
            return new HashSet<>();
        }
        return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
    }

    /**
     * 过滤 source
     * @param from 源数据
     * @param predicate 过滤函数
     * @param <T> 源数据类型
     * @return 过滤后的 List
     */
    public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) {
        if (CollUtil.isEmpty(from)) {
            return new ArrayList<>();
        }
        return from.stream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 将 source 转换为 Map<K, T>
     * @param from 源数据
     * @param keyFunc key 函数
     * @param <T> 源数据类型
     * @param <K> key 类型
     * @return 转换后的 Map
     */
    public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
        if (CollUtil.isEmpty(from)) {
            return new HashMap<>();
        }
        return convertMap(from, keyFunc, Function.identity());
    }

    public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc, Supplier<? extends Map<K, T>> supplier) {
        if (CollUtil.isEmpty(from)) {
            return supplier.get();
        }
        return convertMap(from, keyFunc, Function.identity(), supplier);
    }

    /**
     * 将 source 转换为 Map<K, T>
     * @param from 源数据
     * @param keyFunc key 函数
     * @param valueFunc value 函数
     * @param <T> 源数据类型
     * @param <K> key 类型
     * @param <V> value 类型
     * @return 转换后的 Map
     */
    public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) {
        if (CollUtil.isEmpty(from)) {
            return new HashMap<>();
        }
        return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1);
    }

    /**
     * 将 source 转换为 Map<K, T>
     * @param from 源数据
     * @param keyFunc key 函数
     * @param valueFunc value 函数
     * @param mergeFunction 合并函数
     * @param <T> 源数据类型
     * @param <K> key 类型
     * @param <V> value 类型
     * @return 转换后的 Map
     */
    public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, BinaryOperator<V> mergeFunction) {
        if (CollUtil.isEmpty(from)) {
            return new HashMap<>();
        }
        return convertMap(from, keyFunc, valueFunc, mergeFunction, HashMap::new);
    }

    /**
     * 将 source 转换为 Map<K, T>
     * @param from 源数据
     * @param keyFunc key 函数
     * @param valueFunc value 函数
     * @param <T> 源数据类型
     * @param <K> key 类型
     * @param <V> value 类型
     * @return 转换后的 Map
     */
    public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, Supplier<? extends Map<K, V>> supplier) {
        if (CollUtil.isEmpty(from)) {
            return supplier.get();
        }
        return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1, supplier);
    }

    /**
     * 将 source 转换为 Map<K, T>
     * @param from 源数据
     * @param keyFunc key 函数
     * @param valueFunc value 函数
     * @param mergeFunction 合并函数
     * @param <T> 源数据类型
     * @param <K> key 类型
     * @param <V> value 类型
     * @return 转换后的 Map
     */
    public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, BinaryOperator<V> mergeFunction, Supplier<? extends Map<K, V>> supplier) {
        if (CollUtil.isEmpty(from)) {
            return new HashMap<>();
        }
        return from.stream().collect(Collectors.toMap(keyFunc, valueFunc, mergeFunction, supplier));
    }

    /**
     * 查找第一个满足条件的元素
     * @param from 源数据
     * @param predicate 过滤函数
     * @param <T> 源数据类型
     * @return 转换后的 Set
     */
    public static <T> T findFirst(Collection<T> from, Predicate<T> predicate) {
        return findFirst(from, predicate, Function.identity());
    }

    /**
     * 查找第一个满足条件的元素
     * @param from 源数据
     * @param predicate 过滤函数
     * @param func 转换函数
     * @param <T> 源数据类型
     * @param <U> 转换后的类型
     * @return 转换后的 Set
     */
    public static <T, U> U findFirst(Collection<T> from, Predicate<T> predicate, Function<T, U> func) {
        if (CollUtil.isEmpty(from)) {
            return null;
        }
        return from.stream().filter(predicate).findFirst().map(func).orElse(null);
    }

    /**
     * 判断 source 是否包含 targets 中的任意一个
     * @param source 源数据
     * @param targets 目标数据
     * @return 是否包含
     */
    public static boolean containsAny(Object source, Object... targets) {
        return asList(targets).contains(source);
    }

    /**
     * 判断 collections 是否包含空集合
     * @param collections 源数据
     * @return 是否包含
     */
    public static boolean isAnyEmpty(Collection<?>... collections) {
        return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
    }

    /**
     * 判断集合中是否存在满足条件的元素
     * @param from 来源
     * @param predicate 过滤条件
     * @return 结果
     * @param <T> 集合元素类型
     */
    public static <T> boolean anyMatch(Collection<T> from, Predicate<T> predicate) {
        return from.stream().anyMatch(predicate);
    }


}
